//
// Created by shenhangye on 2025/3/3.
//

#include "AudioPlayer.h"


AudioPlayer::AudioPlayer(FFStatus *ffstatus,int sample_rate,JavaCallHelper *helper) : BasePlayer(ffstatus),sample_rate(sample_rate),javaCallHelper(helper) {
    this->queue=new SafeQueue(ffstatus);
    buffer = static_cast<uint8_t *>(av_malloc(sample_rate * 2 * 2));
    sampleBuffer= static_cast<soundtouch::SAMPLETYPE *>(malloc(sample_rate * 2 * 2));
    soundTouch = new soundtouch::SoundTouch();
    soundTouch->setSampleRate(sample_rate);
    soundTouch->setChannels(2);
    soundTouch->setPitch(pitch);
    soundTouch->setTempo(speed);

    fp_out = fopen(VOL_FILE_PATH, "wb+");
}

AudioPlayer::~AudioPlayer(){
    delete queue;
    delete soundTouch;
    if (fp_out != NULL){
        fclose(fp_out);
    }
}

SLuint32 AudioPlayer::getCurrentSampleRateForOpensles(int sample_rale) {
    int rate = 0;
    switch (sample_rale)
    {
        case 8000:
            rate = SL_SAMPLINGRATE_8;
            break;
        case 11025:
            rate = SL_SAMPLINGRATE_11_025;
            break;
        case 12000:
            rate = SL_SAMPLINGRATE_12;
            break;
        case 16000:
            rate = SL_SAMPLINGRATE_16;
            break;
        case 22050:
            rate = SL_SAMPLINGRATE_22_05;
            break;
        case 24000:
            rate = SL_SAMPLINGRATE_24;
            break;
        case 32000:
            rate = SL_SAMPLINGRATE_32;
            break;
        case 44100:
            rate = SL_SAMPLINGRATE_44_1;
            break;
        case 48000:
            rate = SL_SAMPLINGRATE_48;
            break;
        case 64000:
            rate = SL_SAMPLINGRATE_64;
            break;
        case 88200:
            rate = SL_SAMPLINGRATE_88_2;
            break;
        case 96000:
            rate = SL_SAMPLINGRATE_96;
            break;
        case 192000:
            rate = SL_SAMPLINGRATE_192;
            break;
        default:
            rate =  SL_SAMPLINGRATE_44_1;
    }
    return rate;


}

int AudioPlayer::play_t(void **pcmbuf) {
    data_size=0;
    while(ffstatus!= nullptr&&!ffstatus->exit){
        if (ffstatus->seeking){
            av_usleep(1000*100);
            continue;
        }
        if (ffstatus->isFramePreview){
            av_usleep(1000*100);
            continue;
        }

        if (queue->getQueueSize()==0){
            if (!ffstatus->loading){
                ffstatus->loading = true;
            }
            av_usleep(1000*100);
            continue;
        }else{
            if (ffstatus->loading){
                ffstatus->loading = false;
            }
        }

        std::lock_guard<std::mutex> lock(codecMutex);
        if (isReadFrameFinish){
            avPacket = av_packet_alloc();
            if (queue->getAvPacket(avPacket) != 0){
                av_packet_free(&avPacket);
                av_free(avPacket);
                avPacket = nullptr;
                continue;
            }

            ret= avcodec_send_packet(avCodecConext,avPacket);
            if (ret!=0){
                av_packet_free(&avPacket);
                av_free(avPacket);
                avPacket = nullptr;
                continue;
            }
        }
        avFrame=av_frame_alloc();
        ret= avcodec_receive_frame(avCodecConext,avFrame);
        if (ret!=0){
            char err_buf[1024]={""};
            av_strerror(ret, err_buf, sizeof(err_buf));
            isReadFrameFinish= true;
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = nullptr;
            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = nullptr;
            continue;
        }
        isReadFrameFinish= false;
//        if (avFrame->channels > 0 && avFrame->channel_layout == 0){
//            avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);
//        } else if (avFrame->channels == 0 && avFrame->channel_layout > 0){
//            avFrame->channels = av_get_channel_layout_nb_channels(avFrame->channel_layout);
//        }

//        SwrContext *swrContext;
//        swrContext = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, avFrame->sample_rate,
//                                        avFrame->channel_layout,
//                                        static_cast<AVSampleFormat>(avFrame->format), avFrame->sample_rate, 0, NULL);

//        av_channel_layout_default(channels, &layout);
//        av_channel_layout_nb_channels(&layout);
//        avCodecConext->ch_layout.nb_channels;
//        if (avFrame->channels > 0 && avFrame->channel_layout == 0){
//            avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);
//        } else if (avFrame->channels == 0 && avFrame->channel_layout > 0){
//            avFrame->channels = av_get_channel_layout_nb_channels(avFrame->channel_layout);
//        }
//        av_channel_layout_default(&avFrame->ch_layout, 2);
        SwrContext *swrContext = swr_alloc();
        // 设置输出参数
        ret=av_opt_set_int(swrContext, "out_channel_layout",AV_CH_LAYOUT_STEREO , 0);
        ret=av_opt_set_int(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
        ret=av_opt_set_int(swrContext, "out_sample_rate", avFrame->sample_rate, 0);

//      设置输入参数
        ret=av_opt_set_int(swrContext, "in_channel_layout", avFrame->ch_layout.nb_channels, 0);
        ret=av_opt_set_int(swrContext, "in_sample_fmt", static_cast<AVSampleFormat>(avFrame->format), 0);
        ret=av_opt_set_int(swrContext, "in_sample_rate",  avFrame->sample_rate, 0);

//        AVChannelLayout outChannelLayout= AV_CHANNEL_LAYOUT_STEREO;;
//        AVChannelLayout inChannelLayout= AV_CHANNEL_LAYOUT_STEREO;;
//        outChannelLayout.nb_channels = 2;
//        inChannelLayout.nb_channels = avCodecConext->ch_layout.nb_channels;
//        if (swr_alloc_set_opts2(&swrContext, &outChannelLayout, AV_SAMPLE_FMT_S16, 48000,
//                                &inChannelLayout, avCodecConext->sample_fmt, avCodecConext->sample_rate,
//                                0, nullptr)!= 0)
//        {
//            av_log(nullptr, AV_LOG_ERROR, "swr_alloc_set_opts2 fail.\n");
//            return false;
//        }

//        AVChannelLayout out_layout;
//        av_channel_layout_from_mask(&out_layout, AV_CH_LAYOUT_STEREO);
//        swr_alloc_set_opts2(&swrContext, &out_layout, AV_SAMPLE_FMT_S16, avFrame->sample_rate,
//                                        &(avFrame->ch_layout),
//                                        static_cast<AVSampleFormat>(avFrame->format), avFrame->sample_rate, NULL, NULL);
        ret=swr_init(swrContext);
        if (!swrContext || ret < 0){
            char err_buf[1024]="";
            av_strerror(ret, err_buf, sizeof(err_buf));
            LOGCATE("file error %s",err_buf);
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = nullptr;
            av_frame_free(&avFrame);
            av_free(avFrame);
            avFrame = nullptr;
            swr_free(&swrContext);
            isReadFrameFinish = true;
            continue;
        }


        nb = swr_convert(swrContext, &buffer, avFrame->nb_samples,
                         reinterpret_cast<const uint8_t **>(&avFrame->data), avFrame->nb_samples);
        int out_channels = avFrame->ch_layout.nb_channels;
        data_size = nb * out_channels *av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
        now_frame_time = avFrame->pts * av_q2d(timeBase);
        if (now_frame_time < clock){
            now_frame_time = clock;
        }

        clock = now_frame_time;
        *pcmbuf = buffer;
        av_frame_free(&avFrame);
        av_free(avFrame);
        avFrame = nullptr;
        swr_free(&swrContext);

        break;
    }
    return data_size;
}
int AudioPlayer::getSoundTouchData() {
    while(ffstatus != nullptr && !ffstatus->exit){
        out_buffer= nullptr;
        if (finished){
            finished = false;
            data_size= play_t(reinterpret_cast<void **>(&out_buffer));

            if (data_size>0){
                for(int i = 0; i < data_size / 2 + 1; i++)
                {
                 sampleBuffer[i] = (out_buffer[i * 2] | ((out_buffer[i * 2 + 1]) << 8));
                }
                soundTouch->putSamples(sampleBuffer, nb);
                num = soundTouch->receiveSamples(sampleBuffer, data_size / 4);
            }else{
                soundTouch->flush();
            }
        }
        if (num==0){
            finished=true;
            continue;
        }else{
            if (out_buffer== nullptr){
                num = soundTouch->receiveSamples(sampleBuffer, data_size / 4);
                if(num == 0)
                {
                    finished = true;
                    continue;
                }
            }
            return num;
        }
    }
    return 0;


}

int AudioPlayer::volume_adjust(short *in_buf, float in_vol) {
    int tmp;
    float vol = 20.0 * (in_vol / 100.0);
    tmp = (*in_buf)*vol; // 上面所有关于vol的判断，其实都是为了此处*in_buf乘以一个倍数，你可以根据自己的需要去修改
// 下面的code主要是为了溢出判断
    if(tmp > 32767)
        tmp = 32767;
    else if(tmp < -32768)
        tmp = -32768;
    *in_buf = tmp;

    return 0;

}
void pcmBufferCallBack(SLAndroidSimpleBufferQueueItf bf, void * context){
     auto *audioPlayer=static_cast<AudioPlayer *>(context);
     LOGCATE("pcmBufferCallBack");
     if (audioPlayer!= nullptr){
         int bufferSize = audioPlayer->getSoundTouchData();
         if (bufferSize > 0){
             audioPlayer->clock+=bufferSize / (double)((audioPlayer->sample_rate) * 2 * 2);
             for (int i = 0; i <bufferSize * 2 * 2 ; i+=1) {
                 audioPlayer->volume_adjust((audioPlayer->sampleBuffer + i),audioPlayer->amplifyVol);
             }
             (*audioPlayer->pcmBufferQueue)->Enqueue(bf,audioPlayer->sampleBuffer,bufferSize*2*2);

         }





    }

}
void AudioPlayer::initOpenSLES() {
    SLresult result;
    result = slCreateEngine(&engineObject, 0, 0, 0, 0, 0);
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);

    //第二步，创建混音器
    const SLInterfaceID mids[1] = {SL_IID_ENVIRONMENTALREVERB};
    const SLboolean mreq[1] = {SL_BOOLEAN_FALSE};
    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, mids, mreq);
    (void)result;
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    (void)result;
    result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB, &outputMixEnvironmentalReverb);
    if (SL_RESULT_SUCCESS == result) {
        result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(
                outputMixEnvironmentalReverb, &reverbSettings);
        (void)result;
    }
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&outputMix, 0};


    // 第三步，配置PCM格式信息
    SLDataLocator_AndroidSimpleBufferQueue android_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,2};

    SLDataFormat_PCM pcm={
            SL_DATAFORMAT_PCM,//播放pcm格式的数据
            2,//2个声道（立体声）
            getCurrentSampleRateForOpensles(sample_rate),//44100hz的频率
            SL_PCMSAMPLEFORMAT_FIXED_16,//位数 16位
            SL_PCMSAMPLEFORMAT_FIXED_16,//和位数一致就行
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,//立体声（前左前右）
            SL_BYTEORDER_LITTLEENDIAN//结束标志
    };
    SLDataSource slDataSource = {&android_queue, &pcm};


    const SLInterfaceID ids[4] = {SL_IID_BUFFERQUEUE,SL_IID_MUTESOLO,SL_IID_VOLUME,SL_IID_PLAYBACKRATE};
    const SLboolean req[4] = {SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE};

    (*engineEngine)->CreateAudioPlayer(engineEngine, &pcmPlayerObject, &slDataSource, &audioSnk, 4, ids, req);
    //初始化播放器
    (*pcmPlayerObject)->Realize(pcmPlayerObject, SL_BOOLEAN_FALSE);

//    得到接口后调用  获取Player接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_PLAY, &pcmPlayerPlay);
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_VOLUME, &pcmPlayVolume);
    setVolume(volume);

//    注册回调缓冲区 获取缓冲队列接口
    (*pcmPlayerObject)->GetInterface(pcmPlayerObject, SL_IID_BUFFERQUEUE, &pcmBufferQueue);
    //缓冲接口回调
    (*pcmBufferQueue)->RegisterCallback(pcmBufferQueue, pcmBufferCallBack, this);
//    获取播放状态接口
    (*pcmPlayerPlay)->SetPlayState(pcmPlayerPlay, SL_PLAYSTATE_PLAYING);
    pcmBufferCallBack(pcmBufferQueue, this);

}

void AudioPlayer::OnFrameAvailable(AVFrame *frame) {



}
void *AudioPlayer::start(void *argu) {
    auto* audio= static_cast<AudioPlayer *>(argu);
    audio->initOpenSLES();
    return nullptr;
}


void AudioPlayer::play() {
    m_Thread=std::thread(start,this);
}

void AudioPlayer::setVolume(int volume) {
   this->volume=volume;
}

